#pragma once


#include <iostream>
#include <functional>
#include "Socket.hpp"
#include "Protocol.hpp"

using namespace socket_ns;

// 结构化请求 变为 结构化响应
using process_t = std::function<std::shared_ptr<Response>(std::shared_ptr<Request>)>;


class IOService
{
private:
public:
    IOService(process_t process)
        : _process(process)
    {}

    void IOExecute(SockSPtr iosocket, InetAddr& addr)
    {
        std::string packagestreamqueue;
        while (true)
        {
            // 读取请求报文
            ssize_t n = iosocket->Recv(&packagestreamqueue);
            if (n == 0)
            {
                LOG(WARNING, "Client [%s] quit\n", addr.GetAddrStr().c_str());
                break;
            }
            else if (n < 0)
            {
                LOG(ERROR, "recv() -> Error, errno: %d -> %s\n", errno, strerror(errno));
                break;
            }
            std::cout << "---------------------------------------------------------" << std::endl;
            LOG(INFO, "PackageStreamQueue:\n%s", packagestreamqueue.c_str());

            // 报文解析 
            // 在这里无法保证读到一个完整的报文啊
            // 所以在这里需要确认一下，有没有读到一个完整的报文
            std::string package = Decode(packagestreamqueue);
            if (package.empty()) continue;
            // 在这里就是一个完整的报文
            LOG(INFO, "Package:\n%s", package.c_str());
            auto req = Factory::BuildRequestDefault();

            // 反序列化 
            req->Deserialize(package);

            // 调用上层业务处理请求数据，获取响应数据，再拿来 IO 
            auto resp = _process(req);

            // 构建响应报文，序列化响应报文
            std::string respjson;
            resp->Serialize(&respjson);
            LOG(INFO, "Resp_json:\n%s", respjson.c_str());
            respjson = Encode(respjson);
            LOG(INFO, "Resp_json (Add Head):\n%s", respjson.c_str());

            // 发送回去
            n = iosocket->Send(respjson);
            if (n == 0)
            {
                LOG(WARNING, "Send Nothing?\n");
                break;
            }
            else if (n < 0)
            {
                LOG(ERROR, "Send() -> Error, errno: %d -> %s\n", errno, strerror(errno));
                break;
            }
        }
    }

    ~IOService()
    {}

private:
    process_t _process;
};

